<?php
/**
 * Created by PhpStorm.
 * User: jaylen
 * Date: 2020-04-10
 * Time: 15:01
 */

namespace app\common\service;


use app\common\exception\TokenException;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key;
use think\facade\Config;
use think\facade\Request;

class JWTToken
{
    private $builder = null;
    private $signer = null;
    private $secretKey = null;

    private $secret = '';
    private $expire = 0;
    private $id_prefix = '';

    public function __construct()
    {
        $this->builder = new Builder();
        $this->signer = new Sha256();

        $this->secret = Config::get('token.jwt_token_secret','');
        $this->expire = intval(get_system_config('site_token_expire_in', 7200));
        $this->id_prefix = Config::get('token.jwt_token_id_prefix','tuniao');

        $this->secretKey = new Key($this->secret);
    }

    /**
     * 生成jwt的token令牌
     * @param array $data
     * @return \Lcobucci\JWT\Token
     */
    public function generateJWTToken(array $data = [])
    {
        $now_time = time();
        $jwt_id = $this->id_prefix . strval($now_time);

        $this->builder = $this->builder->issuedBy('http://tuniaokj.com')
            ->identifiedBy($jwt_id, true)
            ->issuedAt($now_time)
//            ->canOnlyBeUsedAfter($now_time + 10)
            ->expiresAt($now_time + $this->expire);

        // 遍历需要自定义的数据
        if (!$data || !empty($data)) {
            foreach ($data as $item => $value) {
                $this->builder = $this->builder->withClaim($item, $value);
            }
        }

        // 生成令牌并设置签名
        return $this->builder->getToken($this->signer, $this->secretKey);
    }

    /**
     * 验证jwt的token是否合法
     * @return array
     */
    public function verifyJWTToken()
    {
        // 获取当前请求的头部中的HTTP_AUTHORIZATION
        $token = Request::header('Authorization','');
        if (!$token) {
            throw new TokenException([
                'msg' => 'Token不能为空',
                'errorCode' => 30001
            ]);
        }

        // 判断token是否合法
        if (strpos($token, 'Bearer ') === false) {
            throw new TokenException();
        }

        // 去掉传入token的前头信息
        $token = str_replace('Bearer ','',$token);

        try {
            // 解析token
            $token = (new Parser())->parse($token);
            // 验证token的合法性或者是否已经过期
            if (!$token->verify($this->signer,$this->secretKey) || $token->isExpired()) {
                throw new TokenException();
            }

            // 验证token对应的id是否有效
            $jwt_token_id = $token->getHeader('jti','');

            // 取出对应的数据
            $claims = $token->getClaims();

            if ($jwt_token_id !== $this->id_prefix . strval($claims['iat']->getValue())) {
                throw new TokenException();
            }

            // 重组用户添加的数据
            $data = [];

            foreach ($claims as $value) {
                if (get_class($value) === 'Lcobucci\JWT\Claim\Basic') {
                    $data[$value->getName()] = $value->getValue();
                }
            }

            return $data;


        } catch (\Exception $e) {
            throw new TokenException();
        }
    }

}